﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="OrdersControl.cs" company="">
//   
// </copyright>
// <summary>
//   The orders control.
// </summary>
// --------------------------------------------------------------------------------------------------------------------


using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Threading;
using System.Windows.Forms;
using Systemathics.FrameWork;

namespace Systemathics.UserControls
{
    [ToolboxBitmap(typeof (OrdersControl), "UserControlsIcon.bmp")]
    public sealed partial class OrdersControl : UserControl
    {
        private readonly Dictionary<Guid, int> orderRow;
        private Guid CurrentStrategyId;
        private Dictionary<Guid, Instrument> Instruments;
        private OrderService orderService;
        private DataGridViewRow RightClickSelectedDataGridViewRow;
        private Instrument selectedInstrument;
        private readonly SynchronizationContext synchronizationContext;
        private readonly SendOrPostCallback UpdateGridOrderDelegate;

        public OrdersControl()
        {
            InitializeComponent();
            Dock = DockStyle.Fill;
            DoubleBuffered = true;

            orderRow = new Dictionary<Guid, int>();
            Instruments = new Dictionary<Guid, Instrument>();

            OrdersDataGridView.Columns["Time"].DefaultCellStyle.Format = "HH:mm:ss.fff";
            OrdersDataGridView.CellValueChanged += OrdersDataGridViewCellValueChanged;

            synchronizationContext = SynchronizationContext.Current;
            UpdateGridOrderDelegate = new SendOrPostCallback(UpdateGridOrder);
        }

        /*
         * il ne faut rien changer ici, excepter qu'a chaque fois qu'on change de strategy et que selectedStrategy est declanché
         * ici, on stock le current strategy Id , de telle sorte que, tous les ordres du datagrid n'ayant pas cet Id de strat deviennet invisibles
         *  et que tous les comming orders n'ayant pas cet id, soit ajouté a la grid, mais en invisible ....
         */
        public Strategy SelectedStrategy
        {
            set
            {
                //Instanciated one time only, cause its the same orderService for  all strategies
                if (orderService == null)
                {
                    orderService = value.orderService;
                    orderService.EmitOrder += OnOrder;
                }
                CurrentStrategyId = value.Id;
                Instruments = value.Instruments;

                foreach (DataGridViewRow dvr in OrdersDataGridView.Rows)
                    dvr.Visible = false;

                foreach (DataGridViewRow dvr in OrdersDataGridView.Rows)
                    if (((Guid)dvr.Cells["Strategy"].Value) == CurrentStrategyId)
                        dvr.Visible = true;
            }
        }
        public Instrument SelectedInstrument
        {
            set
            {
                selectedInstrument = value;
                SelectedInstrumentToolStripButton.Text = selectedInstrument.StaticData.Name;
            }
        }

        private void OnOrder(object sender, Order e)
        {
            synchronizationContext.Post(UpdateGridOrderDelegate, e);
        }
        private void OrdersDataGridViewCellValueChanged(object sender, DataGridViewCellEventArgs e)
        {
            var dgvr = OrdersDataGridView.Rows[e.RowIndex];
            var status = (OrderStatus)dgvr.Cells["Status"].Value;
            if (status == OrderStatus.FILLED || status == OrderStatus.PARTIALLY_FILLED)
                dgvr.DefaultCellStyle.BackColor = Color.LimeGreen;
            else if (status == OrderStatus.ACK || status == OrderStatus.ACK_CANCEL || status == OrderStatus.ACK_MODIFY)
                dgvr.DefaultCellStyle.BackColor = Color.LightGray;
            else if (status == OrderStatus.REJECT || status == OrderStatus.REJECT_CANCEL || status == OrderStatus.REJECT_MODIFY)
                dgvr.DefaultCellStyle.BackColor = Color.Pink;
        }
        private void UpdateGridOrder(Object obj)
        {
            var o = obj as Order;
            var rowNumber = 0;
            lock (o)
            {
                if (orderRow.ContainsKey(o.Id))
                {
                    rowNumber = orderRow[o.Id];
                    OrdersDataGridView["OrderId", rowNumber].Value = o.Id;
                    OrdersDataGridView["Time", rowNumber].Value = o.SendTime;
                    OrdersDataGridView["Side", rowNumber].Value = o.Side;
                    OrdersDataGridView["TargetQty", rowNumber].Value = o.TargetQuantity;
                    OrdersDataGridView["Instrument", rowNumber].Value = o.StaticData.Name;
                    OrdersDataGridView["TargetPrice", rowNumber].Value = o.TargetPrice;
                    OrdersDataGridView["Style", rowNumber].Value = o.Style;
                    OrdersDataGridView["OrderId", rowNumber].Value = o.Id;
                    OrdersDataGridView["Style", rowNumber].Value = o.Style;
                    OrdersDataGridView["ExecutedQty", rowNumber].Value = o.TotalExecutedQuantity;
                    OrdersDataGridView["AveragePrice", rowNumber].Value = o.ExecutedAveragePrice;
                    OrdersDataGridView["RemainingQty", rowNumber].Value = o.RemainingQuantity;
                    OrdersDataGridView["Status", rowNumber].Value = o.Status;
                    OrdersDataGridView["Strategy", rowNumber].Value = o.StrategyId;
                }
                else
                {
                    rowNumber = OrdersDataGridView.Rows.Count;
                    orderRow.Add(o.Id, rowNumber);
                    OrdersDataGridView.Rows.Add(new object[]
                                                    {
                                                        o.Id, o.SendTime, o.Side, o.TargetQuantity, o.StaticData.Name,
                                                        o.TargetPrice, o.Style, o.TotalExecutedQuantity,
                                                        o.ExecutedAveragePrice, o.RemainingQuantity, o.Status,o.StrategyId
                                                    });
                }
                if(o.StrategyId != CurrentStrategyId)
                    OrdersDataGridView.Rows[rowNumber].Visible = false;
            }
        }
        private void SelectedInstrumentToolStripButton_Click(object sender, EventArgs e)
        {
            if (selectedInstrument != null)
            {
                foreach (DataGridViewRow dvr in OrdersDataGridView.Rows)
                    dvr.Visible = true;

                foreach (DataGridViewRow dvr in OrdersDataGridView.Rows)
                    if (dvr.Cells["Instrument"].Value.ToString() != selectedInstrument.StaticData.Name)
                        dvr.Visible = false;
            }
        }
        private void AllOrdersToolStripButton_Click(object sender, EventArgs e)
        {
            foreach (DataGridViewRow dvr in OrdersDataGridView.Rows)
                dvr.Visible = true;
        }
        private void ACKtoolStripButton_Click(object sender, EventArgs e)
        {
            if (selectedInstrument != null)
            {
                foreach (DataGridViewRow dvr in OrdersDataGridView.Rows)
                    dvr.Visible = true;

                foreach (DataGridViewRow dvr in OrdersDataGridView.Rows)
                    if (dvr.Cells["Status"].Value.ToString() != "ACK")
                        dvr.Visible = false;
            }
        }
        private void CancelledToolStripButton_Click(object sender, EventArgs e)
        {
            if (selectedInstrument != null)
            {
                foreach (DataGridViewRow dvr in OrdersDataGridView.Rows)
                    dvr.Visible = true;

                foreach (DataGridViewRow dvr in OrdersDataGridView.Rows)
                    if (dvr.Cells["Status"].Value.ToString() != "ACK_CANCEL")
                        dvr.Visible = false;
            }
        }
        private void OrdersDataGridView_KeyDown(object sender, KeyEventArgs e)
        {
            switch (e.KeyCode)
            {
                case Keys.Up:
                    if (OrdersDataGridView.CurrentCell.RowIndex < OrdersDataGridView.RowCount - 1)
                        OrdersDataGridView.CurrentCell = OrdersDataGridView[OrdersDataGridView.CurrentCell.ColumnIndex, OrdersDataGridView.CurrentCell.RowIndex];
                    break;
                case Keys.Down:
                    OrdersDataGridView.CurrentCell = OrdersDataGridView[OrdersDataGridView.CurrentCell.ColumnIndex, OrdersDataGridView.CurrentCell.RowIndex];
                    break;
                case Keys.F10:
                    if (MessageBox.Show("Execute ATM ?", "Hand Order", MessageBoxButtons.OKCancel) == DialogResult.OK)
                        ATM_Click(this, new EventArgs());
                    break;
                case Keys.F11:
                    if (MessageBox.Show("Cancel this Order ?", "Hand Order", MessageBoxButtons.OKCancel) == DialogResult.OK)
                        Cancel_Click(this, new EventArgs());
                    break;
                case Keys.F12:
                    Modify_Click(this, new EventArgs());
                    break;
            }
        }
        private void OrdersDataGridView_MouseDown(object sender, MouseEventArgs e)
        {
            DataGridView.HitTestInfo Hti;
            if (e.Button == MouseButtons.Right)
            {
                Hti = OrdersDataGridView.HitTest(e.X, e.Y);

                if (Hti.Type == DataGridViewHitTestType.Cell)
                {
                    RightClickSelectedDataGridViewRow = OrdersDataGridView.Rows[Hti.RowIndex];
                    var status = (OrderStatus) RightClickSelectedDataGridViewRow.Cells["Status"].Value;
                    if (status != OrderStatus.ACK_CANCEL || status != OrderStatus.FILLED || status != OrderStatus.REJECT)
                        OrdersContextMenuStrip.Show(OrdersDataGridView, new Point(e.X, e.Y));
                }
            }
        }
        private void ATM_Click(object sender, EventArgs e)
        {
            var Name = (String) RightClickSelectedDataGridViewRow.Cells["Instrument"].Value;
            var Id = (Guid) RightClickSelectedDataGridViewRow.Cells["OrderId"].Value;
            var Side = (OrderSide) RightClickSelectedDataGridViewRow.Cells["Side"].Value;

            Instrument instr = Instruments.Values.Where(t => t.StaticData.Name == Name).FirstOrDefault();
            if (instr != null)
                if (instr.Orders.ContainsKey(Id))
                    switch (Side)
                    {
                        case OrderSide.Buy:
                            instr.Modify(Id, instr.Blotter[QuoteLevel.One].Ask);
                            break;
                        case OrderSide.Sell:
                            instr.Modify(Id, instr.Blotter[QuoteLevel.One].Bid);
                            break;
                    }
        }
        private void Cancel_Click(object sender, EventArgs e)
        {
            var Name = (String) RightClickSelectedDataGridViewRow.Cells["Instrument"].Value;
            var Id = (Guid) RightClickSelectedDataGridViewRow.Cells["OrderId"].Value;

            Instrument instr = Instruments.Values.Where(t => t.StaticData.Name == Name).FirstOrDefault();
            if (instr != null)
                if (instr.Orders.ContainsKey(Id))
                    instr.Cancel(Id);
        }
        private void Modify_Click(object sender, EventArgs e)
        {
            try
            {
                var Name = (String) RightClickSelectedDataGridViewRow.Cells["Instrument"].Value;
                var Id = (Guid) RightClickSelectedDataGridViewRow.Cells["OrderId"].Value;

                Instrument instr = Instruments.Values.Where(t => t.StaticData.Name == Name).FirstOrDefault();
                if (instr != null)
                    if (instr.Orders != null)
                        if (instr.Orders.ContainsKey(Id))
                        {
                            var o = instr.Orders[Id].Clone() as Order;
                            var modif = new ModifyForm();
                            modif.Sidelabel.Text = o.Side.ToString();
                            modif.SideLabelAlso.Text = modif.Sidelabel.Text;
                            modif.Qtylabel.Text = o.TargetQuantity.ToString();
                            modif.Pricelabel.Text = o.TargetPrice.ToString();
                            modif.NewPriceTextBox.Text = modif.Pricelabel.Text;
                            modif.NewQtyTextBox.Text = modif.Qtylabel.Text;

                            if (modif.ShowDialog() == DialogResult.OK)
                            {
                                var NewPrice = Decimal.Parse(modif.NewPriceTextBox.Text);
                                int NewQty = int.Parse(modif.NewQtyTextBox.Text);
                                instr.Modify(Id, NewPrice, NewQty);
                            }
                        }
            }
            catch (Exception)
            {
            }
        }
        private void OrdersDataGridView_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
        {
            if (e.RowIndex < OrdersDataGridView.RowCount)
            {
                var Name = (String) OrdersDataGridView.Rows[e.RowIndex].Cells["Instrument"].Value;
                var Id = (Guid) OrdersDataGridView.Rows[e.RowIndex].Cells["OrderId"].Value;

                Instrument instr = Instruments.Values.Where(t => t.StaticData.Name == Name).FirstOrDefault();
                if (instr != null)
                    if (instr.Orders != null)
                        if (instr.Orders.ContainsKey(Id))
                        {
                            string s = string.Empty;
                            s += string.Format("{0}:\n ", instr.StaticData.Name);

                            switch (instr.Orders[Id].Status)
                            {
                                case OrderStatus.ACK:
                                    s += string.Format("Ack Time : {0}\n", instr.Orders[Id].AckTime);
                                    break;
                                case OrderStatus.REJECT:
                                    s += string.Format("{0}: Reason - {1} \n", instr.Orders[Id].RejectTime, instr.Orders[Id].RejectReason);
                                    break;
                                case OrderStatus.ACK_CANCEL:
                                    s += string.Format("{0}: Ack Cancel at {1} for  Qty - {2} \n", instr.Orders[Id].CancelTime, instr.Orders[Id].CancelAckTime, instr.Orders[Id].CancelQuantity);
                                    break;
                                case OrderStatus.REJECT_CANCEL:
                                    s += string.Format("{0}: Number of Rejections {1} \n", instr.Orders[Id].CancelTime, instr.Orders[Id].CancelRejectionNumber);
                                    break;
                                case OrderStatus.ACK_MODIFY:
                                    s += string.Format("{0}: New Qty/Price -{1} @ {2} \n", instr.Orders[Id].ModifyAckTime, instr.Orders[Id].TargetQuantity, instr.Orders[Id].TargetPrice);
                                    break;
                                case OrderStatus.REJECT_MODIFY:
                                    s += string.Format("{0}: Number of Rejections {1} \n", instr.Orders[Id].ModifyTime, instr.Orders[Id].ModifyRejectedNumber);
                                    break;
                                case OrderStatus.FILLED:
                                    foreach (Execution execution in instr.Orders[Id].Executions)
                                        s += string.Format("{0}: {1} @ {2} - {3}\n", execution.Time, execution.Quantity, execution.Price, execution.Counterparty);
                                    break;
                                case OrderStatus.PARTIALLY_FILLED:
                                    foreach (Execution execution in instr.Orders[Id].Executions)
                                        s += string.Format("{0}: {1} @ {2} - {3}\n", execution.Time, execution.Quantity, execution.Price, execution.Counterparty);
                                    break;
                            }
                            if (OrdersDataGridView.Rows.Count > 0)
                            {
                                DataGridViewCell cell = OrdersDataGridView.Rows[e.RowIndex].Cells[e.ColumnIndex];
                                cell.ToolTipText = s;
                            }
                        }
            }
        }
        private void CopytoolStripButton_Click(object sender, EventArgs e)
        {
            if (OrdersDataGridView.Rows.Count > 0)
            {
                OrdersDataGridView.SelectAll();
                DataObject d = OrdersDataGridView.GetClipboardContent();
                Clipboard.SetDataObject(d);
                MessageBox.Show("Orders Copied To ClipBorad", "Copy Orders", MessageBoxButtons.OK);
            }
        }
    }
}